//
//  TTXMLObject.m
//  Tint
//
//  Created by Kevin Wu on 9/5/12.
//  Copyright (c) 2012 Telligenty. All rights reserved.
//

#import "TTXMLObject.h"

@implementation NSObject (XMLObject)


+ (id)newObjectWithXMLNode:(TTXMLNode *)XMLNode
{
    if ( XMLNode == nil ) {
        return nil;
    }
    
    id object = [[self alloc] init];
    
    NSDictionary *propertyMap = [[self class] newPropertyMap];
    NSDictionary *propertyAttributes = [[self class] newPropertyAttributes];
    
    for ( NSString *nodeName in [propertyMap keyEnumerator] ) {
        
        NSString *propertyName = [propertyMap objectForKey:nodeName];
        id propertyValue = nil;
        
        
        TTXMLNode *node = [[XMLNode elementsForName:nodeName] firstObject];
        TTXMLNode *attr = [XMLNode attributeForName:nodeName];
        
        if ( node ) {
            Class cls = [self classForNodeName:node.name];
            if ( cls ) {
                propertyValue = [cls newObjectWithXMLNode:node];
            } else {
                propertyValue = [node.value copy];
            }
        } else if ( attr ) {
            propertyValue = [attr.value copy];
        }
        
        
        if ( propertyValue ) {
            
            NSString *attribute = [propertyAttributes objectForKey:propertyName];
            
            if ( [attribute hasPrefix:@"Tc"] ) { // BOOL: Tc
                BOOL value = NO;
                if ( [propertyValue respondsToSelector:@selector(boolValue)] ) {
                    value = [propertyValue boolValue];
                }
                NSNumber *v = [[NSNumber alloc] initWithBool:value];
                [object setValue:v forKey:propertyName];
                TTRelease(v);
            } else if ( [attribute hasPrefix:@"Ti"] ) { // int: Ti
                int value = 0;
                if ( [propertyValue respondsToSelector:@selector(intValue)] ) {
                    value = [propertyValue intValue];
                }
                NSNumber *v = [[NSNumber alloc] initWithInt:value];
                [object setValue:v forKey:propertyName];
                TTRelease(v);
            } else if ( [attribute hasPrefix:@"Tq"] ) { // long long: Tq
                long long value = 0;
                if ( [propertyValue respondsToSelector:@selector(longLongValue)] ) {
                    value = [propertyValue longLongValue];
                }
                NSNumber *v = [[NSNumber alloc] initWithLongLong:value];
                [object setValue:v forKey:propertyName];
                TTRelease(v);
            } else if ( [attribute hasPrefix:@"Td"] ) { // double: Td
                double value = 0.0;
                if ( [propertyValue respondsToSelector:@selector(doubleValue)] ) {
                    value = [propertyValue doubleValue];
                }
                NSNumber *v = [[NSNumber alloc] initWithDouble:value];
                [object setValue:v forKey:propertyName];
                TTRelease(v);
            } else if ( [attribute hasPrefix:@"T@\"NSString\""] ) { // NSString: T@"NSString"
                NSString *value = nil;
                if ( [propertyValue isKindOfClass:[NSString class]] ) {
                    value = [propertyValue copy];
                }
                [object setValue:value forKey:propertyName];
                TTRelease(value);
            } else if ( [attribute hasPrefix:@"T@\"NSDate\""] ) { // NSDate: T@"NSDate"
                NSDate *value = nil;
                if ([propertyValue respondsToSelector:@selector(doubleValue)] && 
                    ([propertyValue doubleValue] > 0.0))
                {
                    value = [[NSDate alloc] initWithTimeIntervalSince1970:[propertyValue doubleValue]];
                }
                [object setValue:value forKey:propertyName];
                TTRelease(value);
            } else {
                [object setValue:propertyValue forKey:propertyName];
            }
            
        }
        
        
        TTRelease(propertyValue);
    }
    
    
    TTRelease(propertyMap);
    TTRelease(propertyAttributes);
    
    return object;
}


+ (void)mapToNodeName:(NSString *)nodeName
{
    NSMutableDictionary *translationDictionary = (NSMutableDictionary *)[self translationDictionary];
    [translationDictionary setObject:NSStringFromClass([self class]) forKeyIfNotNil:nodeName];
}

+ (Class)classForNodeName:(NSString *)nodeName
{
    NSString *className = [[self translationDictionary] objectForKey:nodeName];
    return NSClassFromString(className);
}

+ (NSDictionary *)translationDictionary
{
    static NSMutableDictionary *sharedTranslationDictionary = nil;
    if ( sharedTranslationDictionary == nil ) {
        sharedTranslationDictionary = [[NSMutableDictionary alloc] init];
    }
    return sharedTranslationDictionary;
}


+ (NSDictionary *)newPropertyMap
{
    return nil;
}

@end





@implementation NSArray (XMLObject)

+ (NSArray *)newObjectWithXMLNode:(TTXMLNode *)XMLNode
{
    
    if ( XMLNode ) {
        
        NSMutableArray *object = [[NSMutableArray alloc] init];
        
        TTXMLNode *node = [XMLNode firstChild];
        while ( node ) {
            
            Class cls = [self classForNodeName:node.name];
            if ( cls ) {
                id value = [cls newObjectWithXMLNode:node];
                [object addObjectIfNotNil:value];
                TTRelease(value);
            } else {
                [object addObjectIfNotNil:node.value];
            }
            
            node = [node nextSibling];
        }
        
        if ( [object count] < 1 ) {
            TTRelease(object);
        }
        
        return object;
        
    }
    
    return nil;
}

@end





@implementation NSDictionary (XMLObject)

+ (NSDictionary *)newObjectWithXMLNode:(TTXMLNode *)XMLNode
{
    
    if ( XMLNode ) {
        
        NSMutableDictionary *object = [[NSMutableDictionary alloc] init];
        
        TTXMLNode *node = [XMLNode firstChild];
        while ( node ) {
            
            Class cls = [self classForNodeName:node.name];
            if ( cls ) {
                id value = [cls newObjectWithXMLNode:node];
                [object setObject:value forKeyIfNotNil:node.name];
                TTRelease(value);
            } else {
                [object setObject:node.value forKeyIfNotNil:node.name];
            }
            
            node = [node nextSibling];
        }
        
        if ( [object count] < 1 ) {
            TTRelease(object);
        }
        
        return object;
        
    }
    
    return nil;
}

@end



